﻿using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YunQue.Core.Common.Caches
{
    /// <summary>
    /// MemoryCacheManager
    /// </summary>
    public class MemoryCacheManager
    {
        private static MemoryCacheManager instance = null;

        private static readonly object locker = new object();

        private static readonly object acquireLocker = new object();

        private static MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
        private MemoryCacheManager()
        {

        }
        /// <summary>
        /// 获取实例
        /// </summary>
        /// <returns></returns>
        public static MemoryCacheManager GetInstance()
        {
            if (instance == null)
            {
                lock (locker)
                {
                    if (instance == null) instance = new MemoryCacheManager();
                }
            }
            return instance;
        }
        /// <summary>
        /// 获取Key对应的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            return _cache.Get<T>(key);
        }
        /// <summary>
        /// 获取或者创建
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="factory"></param>
        /// <param name="expire"></param>
        /// <returns></returns>
        public T GetOrCreate<T>(string key, Func<ICacheEntry, T> factory, TimeSpan? expire = null)
        {
            if (expire != null)
            {
                return _cache.GetOrCreate(key, entry =>
                {
                    entry.AbsoluteExpirationRelativeToNow = expire.Value;
                    return factory(entry);
                });
            }
            else
            {
                return _cache.GetOrCreate(key, factory);
            }
        }


        /// <summary>
        /// 设置Key对应的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expire"></param>
        public void Set<T>(string key, T value, TimeSpan? expire = null)
        {
            if (expire != null)
            {
                _cache.Set<T>(key, value, expire.Value);
            }
            else
            {
                _cache.Set<T>(key, value);
            }
        }
        /// <summary>
        /// 移除Key对应的值
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            _cache.Remove(key);
        }
        /// <summary>
        /// 限流器
        /// </summary>
        /// <param name="key"></param>
        /// <param name="limit"></param>
        /// <param name="interval"></param>
        /// <returns></returns>
        public bool TryAcquire(string key, int limit, TimeSpan interval)
        {
            bool isLimit = false;
            try
            {
                lock (acquireLocker)
                {
                    var now = DateTime.UtcNow.Ticks;
                    var count = GetList<long>(key).Count(t => t >= now - interval.Ticks);
                    if (count < limit)
                    {
                        var requests = GetList<long>(key);
                        requests.Add(now);
                        if (count == 0)
                        {
                            _cache.Set(key, requests, DateTimeOffset.UtcNow.Add(interval));
                        }
                        else
                        {
                            _cache.Set(key, requests);
                        }
                    }
                    else
                    {
                        isLimit = true;
                    }
                }
            }
            catch (Exception ex)
            {
                isLimit = true;
            }
            return isLimit;
        }
        /// <summary>
        /// 获取集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        private List<T> GetList<T>(string key)
        {
            return _cache.Get<List<T>>(key) ?? new List<T>();
        }
    }
}
